package com.rongxun.base;

import android.content.Context;
import android.support.annotation.CallSuper;
import android.widget.Toast;

import com.google.gson.Gson;
import com.rongxun.hbwallet.model.Response;
import com.rongxun.utils.ALog;
import com.rongxun.utils.MyToast;

import java.io.IOException;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.net.UnknownServiceException;

import io.reactivex.disposables.Disposable;
import io.reactivex.observers.DisposableObserver;
import retrofit2.HttpException;


/**
 * Base Observer 这是一个观察者它决定事件触发的时候将有怎样的行为。
 * RxJava 观察者的事件回调方法除了普通事件onNext()（相当于onClick()/onEvent()）之外，
 * 还定义了两个特殊的事件：onCompleted()和onError()。
 * 的封装处理,对Rxjava 不熟悉，暂时先这样吧。实际的使用还不是很明白
 * <p>
 * 注意内存泄漏：https://github.com/trello/RxLifecycle/tree/2.x
 * <p>
 * Created by zenglb on 2017/4/14.
 */
public abstract class BaseObserver<T> extends DisposableObserver<Response<T>> {
    private final       String TAG                = BaseObserver.class.getSimpleName();
    public final static String Thread_Main        = "main";
    private final       int    RESPONSE_CODE_OK   = 200;       //自定义的业务逻辑，成功返回积极数据
    private final       int    RESPONSE_FATAL_EOR = 500;  //返回数据失败,严重的错误
    private Context mContext;
    private static Gson   gson      = new Gson();
    private        int    errorCode = -1111;
    private        String errorMsg  = "未知的错误！";
    private Disposable disposable;
    private IBase.IView mView;
    /**
     * 根据具体的Api 业务逻辑去重写 onSuccess 方法！Error 是选择重写，but 必须Super ！
     *
     * @param t
     */
    public abstract void onSuccess(T t, Context context);


    /**
     * 不需要显示加载弹出框的请求方式
     *
     * @param
     */
    public BaseObserver() {

    }
    /**
     * 不需要显示加载弹出框的请求方式
     *
     * @param
     */
    public BaseObserver(IBase.IView view) {
        this.mView=view;
    }

    @Override
    protected void onStart() {
        super.onStart();
        if(mView!=null){
            mView.showLoading(true);
        }
    }

    @Override
    public void onNext(Response<T> response) {
    ALog.i("responses",response.getMessage());
        if (Integer.valueOf(response.getCode()) == RESPONSE_CODE_OK) {
            if(mView!=null){
                mView.showLoading(false);
            }
            onSuccess(response.getData(), mContext);
        } else {
           onFailure(Integer.valueOf(response.getCode()), response.getMessage());
        }
    }

    @Override
    public final void onError(Throwable t) {
        if(mView!=null){
            mView.showLoading(false);
        }
        ALog.i("responses",t.getMessage());
        if (t instanceof HttpException) {
            HttpException httpException = (HttpException) t;
            errorCode = httpException.code();
            errorMsg = httpException.getMessage();
            getErrorMsg(httpException);
        } else if (t instanceof SocketTimeoutException) {  //VPN open
            errorCode = RESPONSE_FATAL_EOR;
            errorMsg = "服务器响应超时";
        } else if (t instanceof ConnectException) {
            errorCode = RESPONSE_FATAL_EOR;
            errorMsg = "网络连接异常，请检查网络";
        } else if (t instanceof RuntimeException) {
            errorCode = RESPONSE_FATAL_EOR;
            errorMsg = "运行时错误";
        } else if (t instanceof UnknownHostException) {
            errorCode = RESPONSE_FATAL_EOR;
            errorMsg = "无法解析主机，请检查网络连接";
        } else if (t instanceof UnknownServiceException) {
            errorCode = RESPONSE_FATAL_EOR;
            errorMsg = "未知的服务器错误";
        } else if (t instanceof IOException) {  //飞行模式等
            errorCode = RESPONSE_FATAL_EOR;
            errorMsg = "没有网络，请检查网络连接";
        }
        onFailure(errorCode, errorMsg);
    }

    /**
     * 简单的把Dialog 处理掉
     */
    @Override
    public final void onComplete() {

    }

    /**
     * Default error dispose!
     * 一般的就是 AlertDialog 或 SnackBar
     *
     * @param code
     * @param message
     */
    @CallSuper  //if overwrite,you should let it run.
    public  void onFailure(int code, String message) {
        if(mView!=null){
            mView.showLoading(false);
        }
        if (code == RESPONSE_FATAL_EOR) {
            if(mView!=null){
                mView.showError(message,String.valueOf(code));
            }else{
                MyToast.showToast(mContext,message);
            }
        } else {
            disposeEorCode(message, code);
        }
    }

    /**
     * 对通用问题的统一拦截处理
     *
     * @param code
     */
    private final void disposeEorCode(String message, int code) {
        switch (code) {
            case 101:
            case 112:
            case 123:
            case 401:
                break;
        }
        if (mContext != null && Thread.currentThread().getName().toString().equals(Thread_Main)) {
            ALog.e("捕获异常问题 输出"+errorMsg + "   code=" + errorCode, Toast.LENGTH_SHORT);
            MyToast.showToast(mContext,message);
//            Toast.makeText(mContext, "回调 Retrofit包下的BaseObserver类的disposeEorCode(String message, int code)方法" +
//                    " 捕获异常问题 输出"+errorMsg + "   code=" + errorCode, Toast.LENGTH_LONG).show();
        }
    }
    /**
     * 获取详细的错误的信息 errorCode,errorMsg
     * <p>
     * 以登录的时候的Grant_type 故意写错为例子,这个时候的http 应该是直接的返回401=httpException.code()
     * 但是是怎么导致401的？我们的服务器会在respose.errorBody 中的content 中说明
     */
    private final void getErrorMsg(HttpException httpException) {
        String errorBodyStr = "";
        //        try {      //我们的项目需要的UniCode转码，不是必须要的！
        //            errorBodyStr = TextUtils.convertUnicode(httpException.response().errorBody().string());
        //        } catch (IOException ioe) {
        //            Log.e("errorBodyStr ioe:", ioe.toString());
        //        }
        try {
            Response errorResponse = gson.fromJson(errorBodyStr, Response.class);
            if (null != errorResponse) {
                errorCode = Integer.valueOf(errorResponse.getCode());
                errorMsg = errorResponse.getMessage();

                ALog.e("捕获异常问题 输出"+errorMsg + "   code=" + errorCode, Toast.LENGTH_SHORT);
                Toast.makeText(mContext, "回调 Retrofit包下的BaseObserver类的getErrorMsg(HttpException httpException)方法" +
                        " 捕获异常问题 输出"+errorMsg + "   code=" + errorCode, Toast.LENGTH_LONG).show();

            }
        } catch (Exception jsonException) {
            jsonException.printStackTrace();
        }
    }

}
